package com.lipei.vrp;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.RandomAccessFile;
import java.lang.ProcessBuilder.Redirect;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.ArrayList;
import java.util.UUID;

import org.apache.commons.io.FileUtils;

public class Vrprun {
	private static final String EXPORT_SQL = "export.sql";

	private Opt opt;
	private Vrp vrp;
	private String dbkey;
	private String algoithm;
	private IAlgorithm ialg;
	private String vrppath = null;

	public static void main(String[] args) {
		for (String string : args) {
			System.out.println(string);
		}
		System.out.println(args.length);
		Vrprun run = new Vrprun();
		run.runbyDBkey(args);
	}

	/**
	 * for htCondor
	 * */
	public void runbyVrpFile(String[] args) {
		if (args.length < 2) {
			System.out.println("error in arguement.");
			System.out.println("usage: filename algorithm args");
			return;
		}

		algoithm = args[1];

		EAlgorithm ealg = EAlgorithm.valueOf(algoithm);
		ialg = ealg.getIalg().argsCheck(args);
		if (ialg == null) {
			return;
		}

		try {
			vrppath = args[0];
			vrp = Vrp.vrpReader(args[0]);

			StringBuffer buf = runvrp();
			FileUtils.write(new File(vrppath + ".sql"), buf, false);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public void runbyDBkey(String[] args) {

		if (args.length < 2) {
			System.out.println("error in arguement.");
			System.out.println("usage: name number_of_vehicle upperbound");
			return;
		}

		dbkey = args[0];
		algoithm = args[1];

		EAlgorithm ealg = EAlgorithm.valueOf(algoithm);
		ialg = ealg.getIalg().argsCheck(args);
		if (ialg == null) {
			return;
		}

		try {
			vrppath = runmysql();
			new File(vrppath).deleteOnExit();
			vrp = Vrp.vrpReader(vrppath);

			executeSql(runvrp());
			System.out.println("oyeah!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private StringBuffer runvrp() throws IOException, InterruptedException {

		ArrayList<String> command = ialg.generateCommand(vrppath);

		ProcessBuilder builder = new ProcessBuilder(command);
		builder.redirectInput(Redirect.PIPE);

		final ArrayList<String> list = new ArrayList<String>();
		final Process pro = builder.start();

		Thread vrpthread = new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					InputStream input = pro.getInputStream();

					BufferedReader reader = new BufferedReader(
							new InputStreamReader(input));
					while (true) {
						String readLine;

						readLine = reader.readLine();

						if (readLine == null) {
							break;
						}
						list.add(readLine);

						System.out.println(readLine);
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});

		boolean timeout = false;
		vrpthread.start();
		try {
			vrpthread.join(600000); // 10 minutes
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}

		if (vrpthread.isAlive()) {
			timeout = true;
			pro.destroy();
			vrpthread.join();
		}
		boolean failed = false;
		if (!timeout && pro.exitValue() != 0) {
			failed = true;
		}

		opt = ialg.parse(list, timeout, failed);

		StringBuffer buf = new StringBuffer();
		FiletoDB.optsql(vrp, opt, buf);

		return buf;
	}

	private void executeSql(StringBuffer buf) throws FileNotFoundException,
			IOException, InterruptedException {
		RandomAccessFile lockfile = new RandomAccessFile("lock.lock", "rw");
		FileLock lock = trylock(lockfile);

		try {
			BufferedWriter output = new BufferedWriter(new OutputStreamWriter(
					new FileOutputStream(FiletoDB.OUTPUT_SQL)));
			output.write(buf.toString());
			output.close();

			Main.runSql(FiletoDB.OUTPUT_SQL);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

		lock.close();
		lockfile.close();
	}

	private String runmysql() throws IOException, InterruptedException {
		return runmysql(UUID.randomUUID().toString() + ".vrp", dbkey);
	}

	public static String runmysql(String vrpfilename, String dbkey)
			throws IOException, InterruptedException {

		RandomAccessFile lockfile = new RandomAccessFile(Context.mysqlpath
				+ "lock.lock", "rw");
		FileLock lock = trylock(lockfile);
		{
			File dir = new File(Context.mysqlpath);
			int i = 0;
			do {
				String filename = "test";
				if (i != 0) {
					filename += i;
				}
				filename += ".vrp";
				File file = new File(dir, filename);
				file.delete();

				i++;
			} while (i <= 14);
		}

		StringBuffer buf = new StringBuffer();

		buf.append("set @name='" + dbkey + "';\r\n");
		buf.append("set @targetfile='test.vrp';\r\n");
		buf.append("\r\n");
		buf.append("select @capacity:=capacity from vrp.solomonvrp where name=@name;\r\n");
		buf.append("select @dimension:=count(*) from vrp.solomonvrpdata where solomonvrp=@name;\r\n");
		buf.append("\r\n");
		buf.append("select concat('NAME : ',@name) into outfile '../test1.vrp' fields terminated by ',' lines terminated by '\\r\\n';\r\n");
		buf.append("select 'COMMENT : (solomon, Min no of trucks: 1)' into outfile '../test2.vrp' fields terminated by '?' lines terminated by '\\r\\n';\r\n");
		buf.append("select 'TYPE : CVRP' into outfile '../test3.vrp' fields terminated by ',' lines terminated by '\\r\\n';\r\n");
		buf.append("select concat('DIMENSION : ',@dimension) into outfile '../test4.vrp' fields terminated by ',' lines terminated by '\\r\\n';\r\n");
		buf.append("select 'EDGE_WEIGHT_TYPE : EUC_2D' into outfile '../test5.vrp' fields terminated by ',' lines terminated by '\\r\\n';\r\n");
		buf.append("select concat('CAPACITY : ',@capacity) into outfile '../test6.vrp' fields terminated by ',' lines terminated by '\\r\\n';\r\n");
		buf.append("select 'NODE_COORD_SECTION' into outfile '../test7.vrp' fields terminated by ',' lines terminated by '\\r\\n';\r\n");
		buf.append("\r\n");
		buf.append("select customerno,cast(xcoord as decimal(10,0)),cast(ycoord as decimal(10,0)) from vrp.solomonvrpdata where solomonvrp=@name order by customerno into outfile '../test8.vrp' fields terminated by ' ' lines terminated by '\\r\\n';\r\n");
		buf.append("select 'DEMAND_SECTION'  into outfile '../test9.vrp' fields terminated by ',' lines terminated by '\\r\\n';\r\n");
		buf.append("select customerno,cast(demand as decimal(10,0)) from vrp.solomonvrpdata where solomonvrp=@name order by customerno into outfile '../test10.vrp' fields terminated by ' ' lines terminated by '\\r\\n';\r\n");
		buf.append("select 'DEPOT_SECTION' into outfile '../test11.vrp' fields terminated by ',' lines terminated by '\\r\\n';\r\n");
		buf.append("select ' 1' into outfile '../test12.vrp' fields terminated by ',' lines terminated by '\\r\\n';\r\n");
		buf.append("select ' -1' into outfile '../test13.vrp' fields terminated by ',' lines terminated by '\\r\\n';\r\n");
		buf.append("select 'EOF' into outfile '../test14.vrp' fields terminated by ',' lines terminated by '\\r\\n';\r\n");
		try {
			BufferedWriter output = new BufferedWriter(new OutputStreamWriter(
					new FileOutputStream(EXPORT_SQL)));
			output.write(buf.toString());
			output.close();

			Main.runSql(EXPORT_SQL);

		} catch (Exception e) {
			throw new RuntimeException(e);
		}

		buf = new StringBuffer();
		for (int i = 1; i <= 14; i++) {
			BufferedReader reader = new BufferedReader(
					new InputStreamReader(new FileInputStream(Context.mysqlpath
							+ "test" + i + ".vrp")));

			while (true) {
				String line = reader.readLine();
				if (line == null) {
					break;
				}
				buf.append(line);
				buf.append("\r\n");
			}
			reader.close();
		}
		String string = Context.mysqlpath + vrpfilename;
		FileOutputStream out = new FileOutputStream(string);
		out.write(buf.toString().getBytes());
		out.close();

		lock.close();
		lockfile.close();

		return string;
	}

	private static FileLock trylock(RandomAccessFile lockfile)
			throws IOException, InterruptedException {
		FileChannel channel = lockfile.getChannel();
		while (true) {
			FileLock lock = channel.tryLock();
			if (lock != null) {
				return lock;
			}
			Thread.sleep(200);
		}
	}
}
